package com.shurdroides.proyectofinal.server;

import java.io.IOException;
import java.util.prefs.Preferences;

import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AccountsException;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;



public final class AuthenticatedAppEngineContext implements HttpContext {
	private HttpContext delegate_;
	private CookieStore cookieStore_;
	private static Account account;

	public Account getAccount() {
		return account;
	}

	public static void setAccount(Account a) {
		account = a;
	}

	public static HttpContext newInstance(Context context, String uri,
			Account account) throws AccountsException, AuthenticationException {
		if (context == null)
			throw new IllegalArgumentException("context is null");
		if (account != null)
			setAccount(account);
		return new AuthenticatedAppEngineContext(context, uri);
	}

	private AuthenticatedAppEngineContext(Context context, String uri)
			throws AccountsException, AuthenticationException {
		delegate_ = new BasicHttpContext();
		String authToken = getAuthenticationToken(context);
		DefaultHttpClient httpClient = new DefaultHttpClient();
		try {
			httpClient.getParams().setBooleanParameter(
					ClientPNames.HANDLE_REDIRECTS, false);
			cookieStore_ = new BasicCookieStore();
			setAttribute(ClientContext.COOKIE_STORE, cookieStore_);
			HttpGet http_get = new HttpGet(uri
					+ "/_ah/login?continue=http://localhost/&auth=" + authToken);
			HttpResponse response = httpClient.execute(http_get, this);
			checkResponse(cookieStore_, response);
		} catch (IOException e) {
			throw new AuthenticationException(
					"error getting the authentication cookie", e);
		} finally {
			httpClient = null;
		}

	}

	private void checkResponse(CookieStore cookieStore, HttpResponse response)
			throws AuthenticationException {
		if (response.getStatusLine().getStatusCode() != 302) {
			throw new AuthenticationException(
					"authentication response was not a redirect");
		}
		if (!isAuthenticationCookiePresent(cookieStore)) {
			throw new AuthenticationException(
					"authentication cookie not found in cookie store");
		}
	}

	private String getAuthenticationToken(Context context)
			throws AccountsException {
		String authToken = Helper.getMyPreferences(context).getAuthenticationToken();

		if ("NO_AUTH".equals(authToken)) {
			AccountManager accountManager = AccountManager.get(context);

			if (account == null) {
				throw new AccountsException(
						"no account of type 'com.google' found on this device");
			}

			try {
				Looper.prepare();
				AccountManagerFuture<Bundle> accountManagerFuture = accountManager
						.getAuthToken(account, "ah", null, (Activity) context,
								null, null);

				Bundle authTokenBundle = null;

				authTokenBundle = accountManagerFuture.getResult();
				authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN)
						.toString();
				Helper.getMyPreferences(context)
						.updateAuthenticationToken(authToken);

			} catch (OperationCanceledException e) {
				throw new AccountsException(
						"could not get authentication token from account 'com.google'",
						e);
			} catch (AuthenticatorException e) {
				throw new AccountsException(
						"could not get authentication token from account 'com.google'",
						e);
			} catch (IOException e) {
				throw new AccountsException(
						"could not get authentication token from account 'com.google'",
						e);
			}
		}
		return authToken;
	}

	public boolean isAuthenticationCookiePresent(CookieStore cookieStore) {
		for (Cookie cookie : cookieStore.getCookies()) {
			if (cookie.getName().equals("ACSID")
					|| cookie.getName().equals("SACSID"))
				return true;
		}
		return false;
	}

	public Object getAttribute(String id) {
		return delegate_.getAttribute(id);
	}

	public Object removeAttribute(String id) {
		return delegate_.removeAttribute(id);
	}

	public void setAttribute(String id, Object obj) {
		delegate_.setAttribute(id, obj);
	}

}
